#pragma once
#include <unistd.h>
#include <iostream>
#include <filesystem>
#include <fstream>
#include <ctime>
#include <cassert>
#include <memory>
#include <sstream>
#include "Mutex.hpp"

using namespace MutexMudole;

namespace LogMoudle {

inline std::string format_local_time() {
    std::time_t t = std::time(nullptr);
    std::tm tm_buf{};
#if defined(_WIN32)
    localtime_s(&tm_buf, &t);
#else
    localtime_r(&t, &tm_buf);
#endif
    char buf[64];
    if (std::strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", &tm_buf) == 0)
        return "[time-error]";
    return std::string(buf);
}

const std::string thisPath = "./log.txt";

enum LogLevel { DEBUG, INFO, WARNING, ERROR, FATAL };

inline std::string GetLevelStr(LogLevel level) {
    switch (level) {
        case DEBUG:   return "DEBUG";
        case INFO:    return "INFO";
        case WARNING: return "WARNING";
        case ERROR:   return "ERROR";
        case FATAL:   return "FATAL";
        default:      return "UNKNOWN";
    }
}

class Logstrate {
protected:
    Logstrate() = default;
public:
    virtual void LogPrint(std::string &infor) = 0;
};

/* ---------- 文件日志 ---------- */
class FileLogstrate : public Logstrate {
public:
    FileLogstrate() = default;          // 关键：public
    void LogPrint(std::string &infor) override {
        LockGuard lock(mutex_);
        std::ofstream ofs(thisPath, std::ios::app);
        if (!ofs) {
            std::cerr << "Failed to open log file: " << thisPath << std::endl;
            std::exit(-1);
        }
        ofs << infor << std::endl;
    }
private:
    Mutex mutex_;
};

/* ---------- 屏幕日志 ---------- */
class ScreenLogstrate : public Logstrate {
public:
    ScreenLogstrate() = default;        // 关键：public
    void LogPrint(std::string &infor) override {
        LockGuard lock(mutex_);
        std::cout << infor << std::endl;
    }
private:
    Mutex mutex_;
};

/* ---------- Logger ---------- */
class Logger {
public:
    Logger() { LogConsole(); }
    ~Logger() = default;

    void EnableFileLog() {
        _fflush_strategy = std::make_unique<FileLogstrate>();
    }
    void LogConsole() {
        _fflush_strategy = std::make_unique<ScreenLogstrate>();
    }

    class LogeMessage {
    public:
        LogeMessage(LogLevel level,
                    const std::string& src_name,
                    int line_number,
                    Logger& logger)
            : level_(level),
              str_name_(src_name),
              line_(line_number),
              _pid(getpid()),
              _current_time(format_local_time()),
              logger_(logger)
        {
            std::stringstream ss;
            ss << "[" << _current_time << "]"
               << "[" << GetLevelStr(level) << "]"
               << "[" << _pid << "]"
               << "[" << str_name_ << "]"
               << "[" << line_ << "]"
               << " - ";
            _loginfo = ss.str();
        }

        template<typename T>
        LogeMessage& operator<<(const T& info) {
            std::stringstream ss;
            ss << info;
            _loginfo += ss.str();
            return *this;
        }

        ~LogeMessage() {
            if (logger_._fflush_strategy)
                logger_._fflush_strategy->LogPrint(_loginfo);
        }

    private:
        size_t line_;
        LogLevel level_;
        std::string str_name_;
        std::string _current_time;
        std::string _loginfo;
        pid_t _pid;
        Logger& logger_;
    };

    LogeMessage operator()(LogLevel level,
                          const std::string& src_name,
                          int line_number) {
        return LogeMessage(level, src_name, line_number, *this);
    }

private:
    std::unique_ptr<Logstrate> _fflush_strategy;
};

Logger log;
#define LOG(level) log(level, __FILE__, __LINE__)
#define Enable_Console_Log log.LogConsole()//开启屏幕日志
#define Enable_File_Log log.EnableFileLog()//开启文件日志
}  